package org.inspiration.dudu.user.service.impl;

import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.inspiration.dudu.common.constant.Constant;
import org.inspiration.dudu.common.constant.RedisConstant;
import org.inspiration.dudu.common.exception.ServiceException;
import org.inspiration.dudu.common.pojo.Result;
import org.inspiration.dudu.common.util.EncryptionUtil;
import org.inspiration.dudu.common.util.FileUtil;
import org.inspiration.dudu.common.util.JwtUtil;
import org.inspiration.dudu.common.util.RedisUtil;
import org.inspiration.dudu.user.mapper.UserMapper;
import org.inspiration.dudu.user.model.dto.UserDTO;
import org.inspiration.dudu.user.model.dto.UserInfoDTO;
import org.inspiration.dudu.user.model.entity.UserEntity;
import org.inspiration.dudu.user.model.entity.UserLikeEntity;
import org.inspiration.dudu.user.model.vo.UserVO;
import org.inspiration.dudu.user.service.UserService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final JwtUtil jwtUtil;
    private final RedisUtil redisUtil;
    private final FileUtil fileUtil;
    private final RabbitTemplate rabbitTemplate;


    @Value("${dudu.rabbitmq.exchanges.like-exchange.name}")
    private String likeExchangeName;

    @Value("${dudu.rabbitmq.exchanges.like-exchange.queues.user-like-queue.routing-key}")
    private String userLikeRoutingKey;

    /**
     * 查询所有用户
     *
     * @return 用户视图对象列表
     */
    @Override
    public List<UserVO> getAllUsers() {
        List<UserEntity> list = userMapper.getAllUsers();
        List<UserVO> voList = new ArrayList<>();

        for (UserEntity userEntity : list) {
            voList.add(transToVO(userEntity));
        }
        return voList;
    }

    /**
     * 根据用户ID查询用户
     *
     * @param id 用户ID
     * @return 用户视图对象
     */
    @Override
    public UserVO getUserById(Long id) {
        UserVO userVO = null;

        // 从缓存中获取用户数据
        UserEntity userEntity = redisUtil.queryHashCache(RedisConstant.USER_KEY_PREFIX, id, UserEntity.class,
                userMapper::getUserById, 60L, TimeUnit.SECONDS);
        userVO = transToVO(userEntity);
        return userVO;
    }

    /**
     * 用户登录
     *
     * @param userDTO 用户数据传输对象
     * @return JWT令牌
     */
    @Override
    public String login(UserDTO userDTO) {
        // 判断用户名和密码是否为空
        if (StrUtil.isBlank(userDTO.getUsername()) || StrUtil.isBlank(userDTO.getPassword())) {
            throw new ServiceException(Constant.USER_USERNAME_OR_PASSWORD_IS_BLANK);
        }
        // 查询用户
        UserEntity userEntity = userMapper.getUserByUsername(userDTO.getUsername());

        // 用户不存在
        if (userEntity == null) {
            throw new ServiceException(Constant.USER_LOGIN_ERROR);
        }
        // 检验密码
        if (!userEntity.getPassword().equals(EncryptionUtil.digest(userDTO.getPassword()))) {
            throw new ServiceException(Constant.USER_LOGIN_ERROR);
        }

        return jwtUtil.getToken(userEntity.getId(), userEntity.getUsername());
    }

    /**
     * 将用户实体转换为用户视图对象
     *
     * @param userEntity 用户实体
     * @return 用户视图对象
     */
    @Override
    public UserVO transToVO(UserEntity userEntity) {
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userEntity, userVO);
        return userVO;
    }

    /**
     * 用户注册
     *
     * @param userDTO 用户数据传输对象
     */
    @Override
    public void register(UserDTO userDTO) {
        // 查询用户是否存在
        UserEntity userEntity = userMapper.getUserByUsername(userDTO.getUsername());

        if (userEntity != null) {
            throw new ServiceException(Constant.USER_HAS_EXISTED);
        }
        // 不存在则创建用户
        userDTO.setPassword(EncryptionUtil.digest(userDTO.getPassword()));
        UserEntity user = transToEntity(userDTO);

        userMapper.createUser(user);
    }

    /**
     * 将用户数据传输对象转换为用户实体
     *
     * @param userDTO 用户数据传输对象
     * @return 用户实体
     */
    @Override
    public UserEntity transToEntity(UserDTO userDTO) {
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userDTO, userEntity);
        return userEntity;
    }

    /**
     * 根据token获取用户信息
     *
     * @param token JWT令牌
     * @return 用户视图对象
     */
    @Override
    public UserVO getUserByToken(String token) {
        return UserVO.builder().id(jwtUtil.getIdByToken(token)).username(jwtUtil.getUsernameByToken(token)).build();
    }

    /**
     * 上传用户头像
     *
     * @param id   用户ID
     * @param file 上传的文件
     */
    @Override
    public void uploadAvatar(Long id, MultipartFile file) {
        // 上传图片并获取URL
        String url = fileUtil.uploadImage(file);
        // 更新用户的头像URL
        userMapper.uploadAvatar(id, url);
        // 删除缓存
        redisUtil.deleteKey(RedisConstant.USER_KEY_PREFIX + id);
    }

    /**
     * 增加用户点赞数量
     */
    @Override
    public void increaseLikeCount(UserLikeEntity userLikeEntity) {
        Long userId = userLikeEntity.getUserId();
        // 操作缓存
        String key = RedisConstant.USER_KEY_PREFIX + userId;
        redisUtil.incrementHashFieldWithLua(key, "likeCount");

        //异步同步数据库
        Map<String, Object> map = new HashMap<>();
        map.put("userLikeEntity", userLikeEntity);
        map.put("action", "like");
        rabbitTemplate.convertAndSend(likeExchangeName, userLikeRoutingKey, map);
    }

    /**
     * 减少用户点赞数量
     */
    @Override
    public void decreaseLikeCount(UserLikeEntity userLikeEntity) {
        Long userId = userLikeEntity.getUserId();
        // 修改缓存
        String key = RedisConstant.USER_KEY_PREFIX + userId;
        redisUtil.decrementHashFieldWithLua(key, "likeCount");

        //异步同步数据库
        Map<String, Object> map = new HashMap<>();
        map.put("userLikeEntity", userLikeEntity);
        map.put("action", "unlike");
        rabbitTemplate.convertAndSend(likeExchangeName, userLikeRoutingKey, map);
    }


    /**
     * 增加用户粉丝数量
     *
     * @param followingId 被关注者的用户ID
     */
    @Override
    public void increaseFollowerCount(Long followingId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + followingId;
        redisUtil.incrementHashFieldWithLua(key, "followerCount");
        // 更新数据库
        userMapper.increaseFollowerCount(followingId);

    }

    /**
     * 增加用户关注数量
     *
     * @param followerId 关注者的用户ID
     */
    @Override
    public void increaseFollowingCount(Long followerId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + followerId;
        redisUtil.incrementHashFieldWithLua(key, "followingCount");
        // 改数据库
        userMapper.increaseFollowingCount(followerId);

    }

    /**
     * 减少用户粉丝数量
     *
     * @param followingId 被关注者的用户ID
     */
    @Override
    public void decreaseFollowerCount(Long followingId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + followingId;
        redisUtil.decrementHashFieldWithLua(key, "followerCount");
        // 改数据库
        userMapper.decreaseFollowerCount(followingId);


    }

    /**
     * 减少用户关注数量
     *
     * @param followerId 关注者的用户ID
     */
    @Override
    public void decreaseFollowingCount(Long followerId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + followerId;
        redisUtil.decrementHashFieldWithLua(key, "followingCount");
        // 改数据库
        userMapper.decreaseFollowingCount(followerId);


    }

    /**
     * 根据用户名获取用户ID
     *
     * @param username 用户名
     * @return 用户ID
     */
    @Override
    public Long getUserIdByUsername(String username) {
        return userMapper.getUserIdByUsername(username);
    }

    /**
     * 增加用户文章数量
     *
     * @param userId 用户ID
     */
    @Override
    public void increaseArticleCount(Long userId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + userId;
        redisUtil.incrementHashFieldWithLua(key, "articleCount");
        // 改数据库
        userMapper.increaseArticleCount(userId);


    }

    /**
     * 增加用户问题数量
     *
     * @param userId 用户ID
     */
    @Override
    public void increaseQuestionCount(Long userId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + userId;
        redisUtil.incrementHashFieldWithLua(key, "questionCount");
        // 改数据库
        userMapper.increaseQuestionCount(userId);

    }

    /**
     * 增加用户回答数量
     *
     * @param userId 用户ID
     */
    @Override
    public void increaseAnswerCount(Long userId) {
        // 改缓存
        String key = RedisConstant.USER_KEY_PREFIX + userId;
        redisUtil.incrementHashFieldWithLua(key, "answerCount");
        // 改数据库
        userMapper.increaseAnswerCount(userId);

    }

    @Override
    public void increaseUnreadCommentCount(Long repliedUserId) {
        // 存在则改缓存
        String key = RedisConstant.USER_KEY_PREFIX + repliedUserId;
        redisUtil.incrementHashFieldWithLua(key, "unreadCommentCount");
        userMapper.increaseUnreadCommentCount(repliedUserId);

    }

    @Override
    public void decreaseUnreadLikeCount(Long targetUserId) {

        redisUtil.decrementHashFieldWithLua(RedisConstant.USER_KEY_PREFIX + targetUserId, "unreadLikeCount");
        userMapper.decreaseUnreadLikeCount(targetUserId);
    }

    @Override
    public Boolean isOnline(Long id) {
        return redisUtil.isZSetMemberExists(RedisConstant.ONLINE_USER_KEY, id);
    }

    @Override
    public List<UserVO> getOnlineUsers(Integer pageNum, Integer pageSize) {
        Set<Object> set = redisUtil.getZSetByPage(RedisConstant.ONLINE_USER_KEY, pageNum, pageSize);
        List<UserVO> list = new ArrayList<>();
        for(Object element :set) {
            Long userId = null;
            if(element instanceof Integer) {
                userId = Long.valueOf((Integer)element);
            } else if(element instanceof Long) {
                userId = (Long)element;
            } else {
                throw new ServiceException("类型转换错误");
            }
            list.add(getUserById(userId));
        }
        return list;
    }

    @Override
    public Long onlineUserCount() {
        return redisUtil.getZSetSize(RedisConstant.ONLINE_USER_KEY);
    }

    @Override
    public void decreaseUnreadCommentCount(Long repliedUserId) {
        // 存在则改缓存
        String key = RedisConstant.USER_KEY_PREFIX + repliedUserId;
        redisUtil.decrementHashFieldWithLua(key, "unreadCommentCount");
        userMapper.decreaseUnreadCommentCount(repliedUserId);

    }

    /**
     * 根据用户信息更新用户
     *
     * @param userInfoDTO 用户信息数据传输对象
     */
    @Override
    public void updateUserById(UserInfoDTO userInfoDTO) {
        UserEntity userEntity = transToEntity(userInfoDTO);
        userMapper.updateUserById(userEntity);
        // 删除redis缓存
        redisUtil.deleteKey(RedisConstant.USER_KEY_PREFIX + userInfoDTO.getId());
    }

    /**
     * 将用户信息数据传输对象转换为用户实体
     *
     * @param userInfoDTO 用户信息数据传输对象
     * @return 用户实体
     */
    public UserEntity transToEntity(UserInfoDTO userInfoDTO) {
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userInfoDTO, userEntity);
        return userEntity;
    }

    @Scheduled(fixedRate = 60 * 1000)
    public void cleanExpiredUsers() {
        // 获取当前时间戳
        long currentTime = System.currentTimeMillis();
        // 计算 5 分钟前的时间戳
        long fiveMinutesAgo = currentTime - 5 * 60 * 1000;

        // 获取有序集合中 5 分钟前的所有用户
        Set<Object> expiredUsers = redisUtil.getZSetByScore(RedisConstant.ONLINE_USER_KEY, 0, fiveMinutesAgo);

        if (expiredUsers != null) {
            for (Object userIdObj : expiredUsers) {
                Long userId;
                if (userIdObj instanceof Integer) {
                    userId = ((Integer) userIdObj).longValue();
                } else if (userIdObj instanceof Long) {
                    userId = (Long) userIdObj;
                } else {
                    new Exception("定时器刷新离线用户类型转换问题").printStackTrace();
                    continue;
                }
                // 获取该用户对应的 score（时间戳）
                Double score = redisUtil.getZSetScore(RedisConstant.ONLINE_USER_KEY, userId);
                if (score != null) {
                    long timestamp = score.longValue();
                    // 将时间戳转换为 LocalDateTime
                    LocalDateTime lastActiveTime = Instant.ofEpochMilli(timestamp)
                            .atZone(ZoneOffset.ofHours(8))
                            .toLocalDateTime();

                    // 更新数据库中用户的最近活跃时间
                    userMapper.updateLastActiveTime(userId, lastActiveTime);

                    // 从 Redis 中移除过期用户
                    redisUtil.removeZSet(RedisConstant.ONLINE_USER_KEY, userId);
                }
            }
        }
    }
}
